package com.liveinstars.post.application.controller.content.api;

import com.liveinstars.post.application.controller.content.model.LikeModel;
import com.liveinstars.post.business.model.dto.BaseCommentDTO;
import com.liveinstars.post.business.model.dto.post.BasePostSimpleDTO;
import com.liveinstars.post.business.model.entity.Post;
import com.liveinstars.post.business.model.entity.PostComment;
import com.liveinstars.post.business.model.enums.CommentStatus;
import com.liveinstars.post.business.model.enums.PostStatus;
import com.liveinstars.post.business.model.params.PostCommentParam;
import com.liveinstars.post.business.model.vo.*;
import com.liveinstars.post.business.service.OptionService;
import com.liveinstars.post.business.service.PostCommentService;
import com.liveinstars.post.business.service.PostService;
import com.onepiece.shipelves.common.Result;
import com.onepiece.shipelves.common.enums.SystemExceptionEnum;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.data.web.SortDefault;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.HtmlUtils;

import java.nio.charset.StandardCharsets;
import java.util.List;

import static org.springframework.data.domain.Sort.Direction.DESC;

/**
 * Content post controller.
 *
 * @author johnniang
 * @date 2019-04-02
 */
@Slf4j
@RestController("ApiContentPostController")
@RequestMapping("/post/content/posts")
public class PostController {

    private final PostService postService;

    private final PostCommentService postCommentService;

    private final OptionService optionService;

    public PostController(PostService postService,
                          PostCommentService postCommentService,
                          OptionService optionService) {
        this.postService = postService;
        this.postCommentService = postCommentService;
        this.optionService = optionService;
    }

    @GetMapping
    @ApiOperation("Lists posts")
    public Page<PostListVO> pageBy(@PageableDefault(sort = "createTime", direction = DESC) Pageable pageable,
                                   @RequestParam(value = "uid") Integer uid,
                                   @RequestParam(value = "interestId") Integer interestId,
                                   @RequestParam(value = "status") PostStatus status,
                                   @RequestHeader("uid") Integer userId) {

        Page<Post> postPage = null;
        if(uid != null && !uid.equals(0)){
            //分别查找待审核和已经审核
            if(status != null){
                postPage = postService.pageByUser(status, pageable, uid);
            }else {
                //查询全部
                postPage = postService.pageByUser(pageable, uid);
            }
        }else if(interestId != null && !interestId.equals(0)){
            postPage = postService.pageByInterest(PostStatus.PUBLISHED, pageable, interestId);
        }else {
            postPage = postService.pageBy(PostStatus.PUBLISHED, pageable);
        }
        return postService.convertToListVo(postPage, userId);
    }

    @GetMapping("/user")
    @ApiOperation("Lists posts")
    public Page<PostListVO> pageByUser(@PageableDefault(sort = "createTime", direction = DESC) Pageable pageable, @RequestParam(value = "uid") Integer uid, @RequestHeader("uid") Integer userId) {
        Page<Post> postPage = postService.pageByUser(PostStatus.PUBLISHED, pageable, uid);
        return postService.convertToListVo(postPage, userId);
    }

    @GetMapping("/collect")
    @ApiOperation("Lists posts")
    public Page<PostListVO> pageByCollect(@PageableDefault(sort = "createTime", direction = DESC) Pageable pageable, @RequestHeader("uid") Integer userId) {
        Page<Post> postPage = postService.pageByCollect(PostStatus.PUBLISHED, pageable, userId);
        return postService.convertToListVo(postPage, userId);
    }

    @GetMapping("/interest")
    @ApiOperation("Lists posts")
    public Page<PostListVO> pageByInterest(@PageableDefault(sort = "createTime", direction = DESC) Pageable pageable, @RequestParam(value = "interestId") Integer interestId, @RequestHeader("uid") Integer userId) {
        Page<Post> postPage = postService.pageByInterest(PostStatus.PUBLISHED, pageable, interestId);
        return postService.convertToListVo(postPage, userId);
    }


    @PostMapping(value = "search")
    @ApiOperation("Lists posts by keyword")
    public Page<BasePostSimpleDTO> pageBy(@RequestParam(value = "keyword") String keyword,
                                          @PageableDefault(sort = "createTime", direction = DESC) Pageable pageable) {
        Page<Post> postPage = postService.pageBy(keyword, pageable);
        return postService.convertToSimple(postPage);
    }

//    @GetMapping(value = "/admin")
//    @ApiOperation("Lists posts by keyword")
//    public Page<BasePostSimpleDTO> pageByAdmin(
//                                          @PageableDefault(sort = "createTime", direction = DESC) Pageable pageable) {
//        Page<Post> postPage = postService.pageByAdmin(pageable);
//        return postService.convertToSimple(postPage);
//    }

    @GetMapping("{postId:\\d+}")
    @ApiOperation("Gets a post")
    public PostDetailVO getBy(@PathVariable("postId") Integer postId,
                              @RequestParam(value = "formatDisabled", required = false, defaultValue = "true") Boolean formatDisabled,
                              @RequestParam(value = "sourceDisabled", required = false, defaultValue = "false") Boolean sourceDisabled,
                              @RequestHeader("uid") Integer userId) {
        PostDetailVO postDetailVO = postService.convertToDetailVoByUserId(postService.getById(postId), userId);

        if (formatDisabled) {
            // Clear the format content
            postDetailVO.setFormatContent(null);
        }

        if (sourceDisabled) {
            // Clear the original content
            postDetailVO.setOriginalContent(null);
        }

        postService.publishVisitEvent(postDetailVO.getId());

        return postDetailVO;
    }

    @GetMapping("/slug")
    @ApiOperation("Gets a post")
    public PostDetailVO getBy(@RequestParam("slug") String slug,
                              @RequestParam(value = "formatDisabled", required = false, defaultValue = "true") Boolean formatDisabled,
                              @RequestParam(value = "sourceDisabled", required = false, defaultValue = "false") Boolean sourceDisabled) {
        PostDetailVO postDetailVO = postService.convertToDetailVo(postService.getBySlug(slug));

        if (formatDisabled) {
            // Clear the format content
            postDetailVO.setFormatContent(null);
        }

        if (sourceDisabled) {
            // Clear the original content
            postDetailVO.setOriginalContent(null);
        }

        postService.publishVisitEvent(postDetailVO.getId());

        return postDetailVO;
    }

    @GetMapping("{postId:\\d+}/comments/top_view")
    public Page<CommentWithHasChildrenVO> listTopComments(@PathVariable("postId") Integer postId,
                                                          @RequestParam(name = "page", required = false, defaultValue = "0") int page,
                                                          @SortDefault(sort = "createTime", direction = DESC) Sort sort) {

        return postCommentService.pageTopCommentsBy(postId, CommentStatus.PUBLISHED, PageRequest.of(page, optionService.getCommentPageSize(), sort));
    }


    @GetMapping("{postId:\\d+}/comments/{commentParentId:\\d+}/children")
    public List<BaseCommentDTO> listChildrenBy(@PathVariable("postId") Integer postId,
                                               @PathVariable("commentParentId") Long commentParentId,
                                               @SortDefault(sort = "createTime", direction = DESC) Sort sort) {
        // Find all children comments
        List<PostComment> postComments = postCommentService.listChildrenBy(postId, commentParentId, CommentStatus.PUBLISHED, sort);
        // Convert to base comment dto

        return postCommentService.convertTo(postComments);
    }

    @GetMapping("{postId:\\d+}/comments/tree_view")
    @ApiOperation("Lists comments with tree view")
    public Page<BaseCommentVO> listCommentsTree(@PathVariable("postId") Integer postId,
                                                @RequestParam(name = "page", required = false, defaultValue = "0") int page,
                                                @SortDefault(sort = "createTime", direction = DESC) Sort sort) {
        return postCommentService.pageVosBy(postId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
    }

    @GetMapping("{postId:\\d+}/comments/list_view")
    @ApiOperation("Lists comment with list view")
    public Page<BaseCommentWithParentVO> listComments(@PathVariable("postId") Integer postId,
                                                      @RequestParam(name = "page", required = false, defaultValue = "0") int page,
                                                      @SortDefault(sort = "createTime", direction = DESC) Sort sort) {
        Page<BaseCommentWithParentVO> result = postCommentService.pageWithParentVoBy(postId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
        return result;
    }

    @PostMapping("comments")
    @ApiOperation("Comments a post")
    public BaseCommentDTO comment(@RequestBody PostCommentParam postCommentParam) {
        postCommentService.validateCommentBlackListStatus();

        // Escape content
        postCommentParam.setContent(HtmlUtils.htmlEscape(postCommentParam.getContent(), StandardCharsets.UTF_8.displayName()));
        return postCommentService.convertTo(postCommentService.createBy(postCommentParam));
    }


    @PostMapping("{postId:\\d+}/likes")
    @ApiOperation("Likes a post")
    public Result<LikeModel> like(@PathVariable("postId") Integer postId, @RequestHeader("uid") Integer userId) {
        if (userId == null || userId == 0) {
            Result result = SystemExceptionEnum.NO_LOGIN.createResult();
            return result;
        }
        Result<LikeModel> result = new Result<>();
        postService.increaseLike(postId, userId);
        Boolean match = postService.matchLikeRelation(postId, userId);
        LikeModel model = new LikeModel();
        if (match) {
            model.setMatch(match);
            model.setUserId(userId);
            result.setData(model);
        } else {
            result.setData(model);
        }
        return result;
    }

    @PostMapping("{postId:\\d+}/unLikes")
    @ApiOperation("Likes a post")
    public Result<LikeModel> unLike(@PathVariable("postId") Integer postId, @RequestHeader("uid") Integer userId) {
        if (userId == null || userId == 0) {
            Result result = SystemExceptionEnum.NO_LOGIN.createResult();
            return result;
        }
        postService.decreaseLike(postId, userId);
        Result<LikeModel> result = new Result<>();
        LikeModel model = new LikeModel();
        result.setData(model);
        return result;
    }

    @PostMapping("{postId:\\d+}/collect")
    @ApiOperation("collect a post")
    public Result<Boolean> collect(@PathVariable("postId") Integer postId, @RequestHeader("uid") Integer userId) {
        if (userId == null || userId == 0) {
            Result result = SystemExceptionEnum.NO_LOGIN.createResult();
            return result;
        }
        postService.collectPost(postId, userId);
        Result<Boolean> result = new Result<>();
        result.setData(true);
        return result;
    }



    @PostMapping("{postId:\\d+}/unCollect")
    @ApiOperation("uncollect a post")
    public Result<Boolean> unCollect(@PathVariable("postId") Integer postId, @RequestHeader("uid") Integer userId) {
        if (userId == null || userId == 0) {
            Result result = SystemExceptionEnum.NO_LOGIN.createResult();
            return result;
        }
        postService.unCollectPost(postId, userId);
        Result<Boolean> result = new Result<>();
        result.setData(true);
        return result;
    }

    @PostMapping("{postId:\\d+}/increaseVisit")
    @ApiOperation("increaseVisit a post")
    public Result<Boolean> increaseVisit(@PathVariable("postId") Integer postId) {
        postService.increaseVisit(1, postId);
        Result<Boolean> result = new Result<>();
        result.setData(true);
        return result;
    }
}
